package com.xunk.equipment.job;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xunk.common.core.constant.CacheConstants;
import com.xunk.common.core.enums.SupplierEnum;
import com.xunk.common.core.utils.*;
import com.xunk.common.redis.service.RedisService;
import com.xunk.equipment.config.EquipmentConfig;
import com.xunk.equipment.domain.EquipmentDO;
import com.xunk.equipment.mapper.EquipmentMapper;
import com.xunk.equipment.service.BaseService;
import com.xunk.equipment.service.ruying.RuYingControlService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.*;

/**
 * @ProjectName: xunk
 * @Package: com.xunk.buz.job
 * @ClassName: FixSceneJob
 * @Author: dongxiaoxin
 * @Description: 固定场景实现
 * @Date: 2021/4/8 15:02
 * @Version: 1.0
 */
@Component
@EnableScheduling
@Slf4j
public class DeviceOnlineQueryJob {

    final String deviceOnlineQuery = "0 0/30 * * * ? ";

    @Autowired
    EquipmentMapper equipmentMapper;

    @Autowired
    RedisService redisService;

    @Autowired
    BaseService baseService;

    @Autowired
    EquipmentConfig equipmentConfig;

    @Autowired
    RuYingControlService ruYingControlService;

    @Scheduled(cron = deviceOnlineQuery)
    public void ruyingDeviceOnlineQueryJob() {
        log.info("执行静态定时任务时间: {}", LocalDateTime.now());
        // 查询当前可用家庭对应的ownerId
        String dimKey = CacheConstants.FIND_OWNID_BY_DEPTID + "*";
        Collection<String> keys = redisService.keys(dimKey);
        if (DataUtils.isNotEmpty(keys)) {
            keys.parallelStream().forEach(key -> {
                String[] split = key.split(":");
                Long deptId = Long.valueOf(split[split.length - 1]);
                String ownerId = redisService.getCacheObject(key);
                // 获取如影设备列表
                String deviceUrl = equipmentConfig.getDevicesUrl();
                Map<String, String> header = HttpUtil.getHeader4Ruying(equipmentConfig.getAppId(), JwtUtil.getRuyingGwt(equipmentConfig.getSerectKey(), ownerId));
                JSONObject response = HttpUtil.doGetstr(deviceUrl, header);
                log.info("DEPT {}  ,  查询如影平台信息 {}", deptId, JSON.toJSONString(response));
                Optional<JSONArray> devicesOptional = Optional.ofNullable(response).map(s -> s.getJSONObject("data")).map(s -> s.getJSONArray("devices"));
                if (devicesOptional.isPresent()) {
                    Map<String, Long> deviceOnlineState = new HashMap<>();
                    JSONArray devices = devicesOptional.get();
                    // 获取父设备id
                    String parentSn = null;
                    for (Object device : devices) {
                        JSONObject d = ((JSONObject) device);
                        String did = d.getString("did");
                        deviceOnlineState.put(did, -1L);
                        Integer status = d.getInteger("status");
                        if (Objects.equals(status, 0)) {
                            Boolean online = d.getJSONObject("summary").getBoolean("online");
                            parentSn = Optional.ofNullable(parentSn).orElseGet(() -> d.getJSONObject("summary").getString("parentId"));
                            deviceOnlineState.put(did, online ? 1L : 0L);
                        }
                    }
                    // 通过deptId查询本地的设备列表
                    List<EquipmentDO> equipmentDOS = equipmentMapper.listEquipments(deptId, 0);
                    // 暂时只管哪些是删除的，哪些是需要修改在线状态的（增加的设备暂时不管）
                    for (EquipmentDO equipmentDO : equipmentDOS) {
                        String deviceSn = equipmentDO.getDeviceSn();
                        String supplier = equipmentDO.getSupplier();
                        // 不是如影设备的话，不操作
                        if (!Objects.equals(SupplierEnum.parseSupplierEnum(supplier), SupplierEnum.RUYING)) {
                            continue;
                        }
                        Long online = deviceOnlineState.get(deviceSn);
                        // r如果存在该设备，状态0/1/-1,不存在则删除。
                        String ancestor = baseService.findAncestorByDeptId(deptId);
                        String cacheKey = ancestor.concat(":").concat(deviceSn);
                        if (DataUtils.isEmpty(online)) {
//                             TODO 后面要解开这个或者就这样不处理，对于应该删除的，需要人工介入一下
                            // 设备移除时删除设备影子缓存
                            redisService.deleteObject(cacheKey);
                            redisService.deleteObject(CacheConstants.EQUIPMENT_INFO_KEY + ":" + deviceSn);
                            equipmentMapper.deleteEquipment(deviceSn, equipmentDO.getParentSn());
                            continue;
                        }
                        if (Objects.equals(online, -1L)) {
                            // 状态为-1，不予修改(没有查到)
                            continue;
                        }
                        Long deviceOnline = equipmentDO.getDeviceOnline();
                        log.info("{} 当前设备状态 {}, 查询的设备状态 {}", deviceSn, deviceOnline, online);

//                        if (Objects.equals(online, 1L)) {
//                            ruYingControlService.getShadowsCache(deptId, deviceSn, cacheKey);
//                        }
                        ruYingControlService.cacheRuyingEquipmentProperty(equipmentDO.getDeptId(), deviceSn, "online", String.valueOf(deviceOnline));
                        if (!Objects.equals(online, deviceOnline)) {
                            equipmentMapper.updateEquipmentOnline(deviceSn, online);
                        }
                    }
                }
            });
        }
    }

    /**
     * 安科瑞网关在线状态确认,超过3分钟没有心跳确认就讲设备状态更改为离线
     */
    @Scheduled(cron = "0 0/5 * * * ?")
    public void acrelGateOnlineConfirm() {

        List<EquipmentDO> devices = equipmentMapper.selectDeviceBySupplier("acrel");
        devices.parallelStream().forEach(device -> {
            String gateId = device.getDeviceSn().split(":")[0];
            String dateStr = redisService.getCacheObject(CacheConstants.ACREL_HEARTBEAT_TIME + gateId);
            if (StringUtils.isNotEmpty(dateStr) && DateUtils.addMinutes(DateUtils.parseDate(dateStr), 10).getTime() < new Date().getTime()) {
                log.info(device.getDeptId() + "家的" + device.getDeviceName() + "已掉线...");
                equipmentMapper.updateEquipmentOnline(device.getDeviceSn(), 0L);
            }
        });
    }

}
